package com.yjzx.util;

import com.yjzx.care.*;
import com.yjzx.care.base.BaseLoop;
import com.yjzx.care.functional.ToBoolFunction;

import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import static com.yjzx.care.base.ElementFactoryEnum.*;

/**
 * @author yjzx
 * @date 2023/12/15
 * @description ElementUtil(builder类在调用builder后才执行)
 */
public class ElementUtil {
    private ElementUtil() {
    }
    
    /**
     * 无返回值 if判断
     *
     * @param whether  判断语句
     * @param runnable 实现
     */
    public static ElementNoReturn.NoReturnElse ifExist(boolean whether, Runnable runnable) {
        return ifExistNoReturn().ifExist(whether, runnable);
    }

    /**
     * 无返回值 if判断
     */
    public static ElementNoReturn ifExistNoReturn() {
        return NO_RETURN_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 有返回值 if判断
     *
     * @param whether  判断语句
     * @param consumer 实现
     * @param <T>      返回值变量类型
     */
    public static <T> ElementReturn.ElseReturn<T> ifExist(boolean whether, Supplier<T> consumer) {
        return ElementUtil.<T>ifExistReturn().ifExist(whether, consumer);
    }

    /**
     * 有返回值 if判断
     */
    public static <T> ElementReturn<T> ifExistReturn() {
        return RETURN_TYPE_CLASS.elementNewInstance();
    }

    /**
     * for循环（判断和循环中的变量需要为引用变量，建议使用 RefValue包裹）
     *
     * @param value        引用类型变量
     * @param judge        判断语句
     * @param judgeUpdater 循环中变量更新
     * @param loopBody     循环体
     * @param <T>          变量类型
     * @return
     */
    public static <T> LoopFor<T> loopFor(T value, ToBoolFunction<T> judge, Function<T, T> judgeUpdater, Consumer<LoopFor<T>> loopBody) {
        return ElementUtil.<T>loopFor().loopBody(value, judge, judgeUpdater, loopBody);
    }

    /**
     * for循环（判断和循环中的变量需要为引用变量，建议使用 RefValue包裹）
     */
    public static <T> LoopFor<T> loopFor() {
        return LOOP_FOR_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 有返回值 while循环
     *
     * @param judge    判断语句
     * @param loopBody 循环体，返回值为修改后的变量
     * @return
     */
    public static LoopWhile loopWhile(BooleanSupplier judge, Consumer<LoopWhile> loopBody) {
        return loopWhile().loopBody(judge, loopBody);
    }

    /**
     * 有返回值 while循环
     */
    public static LoopWhile loopWhile() {
        return LOOP_WHILE_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 有返回值 do...while循环
     *
     * @param judge    判断语句
     * @param loopBody 循环体，返回值为修改后的变量
     * @return
     */
    public static LoopDoWhile loopDoWhile(BooleanSupplier judge, Consumer<LoopDoWhile> loopBody) {
        return loopDoWhile().loopBody(judge, loopBody);
    }

    /**
     * 有返回值 do...while循环
     */
    public static LoopDoWhile loopDoWhile() {
        return LOOP_DO_WHILE_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 无返回值 if判断
     *
     * @param whether  判断语句
     * @param runnable 实现
     */
    public static ElementNoReturn.ElementNoReturnBuilder.NoReturnElseBuilder ifExistNoReturnBuilder(boolean whether, Runnable runnable) {
        return ifExistNoReturnBuilder().ifExistToBuilder(whether, runnable);
    }

    /**
     * 无返回值 if判断
     */
    public static ElementNoReturn.ElementNoReturnBuilder ifExistNoReturnBuilder() {
        return NO_RETURN_BUILDER_TYPE_CLASS.elementNewInstance();
    }


    /**
     * 有返回值 if判断
     *
     * @param whether  判断语句
     * @param consumer 实现
     * @param <T>      返回值变量类型
     */
    public static <T> ElementReturn.ElementReturnBuilder.ReturnElseBuilder<T> ifExistReturnBuilder(boolean whether, Supplier<T> consumer) {
        return ElementUtil.<T>ifExistReturnBuilder().ifExistToBuilder(whether, consumer);
    }

    /**
     * 有返回值 if判断
     */
    public static <T> ElementReturn.ElementReturnBuilder<T> ifExistReturnBuilder() {
        return RETURN_BUILDER_TYPE_CLASS.elementNewInstance();
    }


    /**
     * for循环（判断和循环中的变量需要为引用变量，建议使用 RefValue包裹）
     *
     * @param value        引用类型变量
     * @param judge        判断语句
     * @param judgeUpdater 循环中变量更新
     * @param loopBody     循环体
     * @param <T>          变量类型
     * @return
     */
    public static <T> LoopFor.LoopForBuilder<T> loopForBuilder(T value, ToBoolFunction<T> judge, Function<T, T> judgeUpdater, Consumer<LoopFor<T>> loopBody) {
        return ElementUtil.<T>loopForBuilder().set(value, judge, judgeUpdater, loopBody);
    }

    /**
     * for循环（判断和循环中的变量需要为引用变量，建议使用 RefValue包裹）
     */
    public static <T> LoopFor.LoopForBuilder<T> loopForBuilder() {
        return LOOP_FOR_BUILDER_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 有返回值 while循环
     *
     * @param judge    判断语句
     * @param loopBody 循环体，返回值为修改后的变量
     * @return
     */
    public static LoopWhile.LoopWhileBuilder loopWhileBuilder(BooleanSupplier judge, Consumer<LoopWhile> loopBody) {
        return loopWhileBuilder().set(judge, loopBody);
    }

    /**
     * 有返回值 while循环
     */
    public static LoopWhile.LoopWhileBuilder loopWhileBuilder() {
        return LOOP_WHILE_BUILDER_TYPE_CLASS.elementNewInstance();
    }

    /**
     * 有返回值 do...while循环
     *
     * @param judge    判断语句
     * @param loopBody 循环体，返回值为修改后的变量
     * @return
     */
    public static LoopDoWhile.LoopDoWhileBuilder loopDoWhileBuilder(BooleanSupplier judge, Consumer<LoopDoWhile> loopBody) {
        return loopDoWhileBuilder().set(judge, loopBody);
    }

    /**
     * 有返回值 do...while循环
     */
    public static LoopDoWhile.LoopDoWhileBuilder loopDoWhileBuilder() {
        return LOOP_DO_WHILE_BUILDER_TYPE_CLASS.elementNewInstance();
    }

    public static void main(String[] args) {
        ifExist(false, () -> System.out.println(1)).otherwise(()-> System.out.println(2));
        System.out.println(ifExist(false, () -> 1).otherwise(()-> 2));
        loopFor(0,x->x<10,x->--x, System.out::print);
        loopWhile(()->true, BaseLoop::toBreak);
        loopDoWhile(()->false, BaseLoop::toBreak);
        final String str ="builder类只有调用build才会执行";
        ifExistNoReturnBuilder(false, () -> System.out.println(1)).otherwiseBuild(()-> System.out.println(2));
        System.out.println(ifExistReturnBuilder(false, () -> 1).otherwiseBuild(()-> 2).get());
        loopForBuilder(0,x->x<10,x->--x, System.out::print).build();
        loopWhileBuilder(()->true, BaseLoop::toBreak).build();
        loopDoWhileBuilder(()->false, BaseLoop::toBreak).build();
    }
}
